<script lang="ts" setup>
import type { WorkerMessage } from './spectrum-view.worker';

import { defineExpose, onMounted, onUnmounted, ref } from 'vue';

// eslint-disable-next-line n/no-extraneous-import
import { v4 as uuidv4 } from 'uuid';

const props = defineProps({
  // chooseShow: {
  //   type: Boolean,
  //   default: false,
  //   required: false, // 是否必传
  // },
  // showMode: {
  //   type: Number,
  //   default: 5,
  //   required: false, // 是否必传
  // },
  // X轴后缀
  freqSuffix: {
    type: String,
    default: 'Hz',
    required: false, // 是否必传
  },
  // Y轴后缀
  levelSuffix: {
    type: String,
    default: 'dBm',
    required: false, // 是否必传
  },
});

// 初始化 Worker（网页4）
const worker = new Worker(new URL('spectrum-view.worker.ts', import.meta.url), {
  type: 'module', // 必须声明模块类型
});

const canvas_id = uuidv4();
const div_id = uuidv4();

let resizeObserver: null | ResizeObserver = null;

// const proxy = getCurrentInstance();
/**
 * 选择区域
 */
interface SelectRange {
  end: number;
  start: number;
}

/**
 * 频率范围
 */
interface FreqRange {
  left: number;
  right: number;
}

/**
 * 电平范围
 */
interface LevelRange {
  bottom: number;
  top: number;
}

class ViewRect {
  bottom: number;
  height: number;
  left: number;
  right: number;
  top: number;
  width: number;
  constructor(left: number, right: number, top: number, bottom: number) {
    this.left = left;
    this.right = right;
    this.top = top;
    this.bottom = bottom;
    this.width = right - left;
    this.height = bottom - top;
  }
}

// interface DrawPoint {
//   x: number;
//   y: number;
// }

enum ShowModeEnum {
  // eslint-disable-next-line no-unused-vars
  FFT = 1, // '频域图'
  // eslint-disable-next-line no-unused-vars
  FFT_FULL = 5, // '频域+瀑布图'
  // eslint-disable-next-line no-unused-vars
  FFT_WAVE = 4, // '频域+时域图'
  // eslint-disable-next-line no-unused-vars
  FULL = 3, // '瀑布图'
  // eslint-disable-next-line no-unused-vars
  WAVE = 2, // '时域图'
}

const showMode = ref<ShowModeEnum>(ShowModeEnum.FFT_FULL); // 显示类型
let fftRect: ViewRect = new ViewRect(10, 1000, 10, 500); // 频域图区域
let freqRect: ViewRect = new ViewRect(10, 1000, 10, 500); // 频率刻度区域
let levelRect: ViewRect = new ViewRect(10, 1000, 10, 500); // 电平刻度区域
let fullRect: ViewRect = new ViewRect(10, 1000, 10, 500); // 瀑布图区域
let legendRect: ViewRect = new ViewRect(10, 1000, 10, 500); // 图例区域
let waveRect: ViewRect = new ViewRect(10, 1000, 10, 500); // 波形图区域
const leftPadding = 10;
const rightPadding = 50;
const topPadding = 10;
const bottomPadding = 25;

let freqRange: FreqRange = { left: 0, right: 1000 }; // 频率范围
let showFreqRange: FreqRange = { left: 0, right: 1000 }; // 显示频率范围
const levelRange: LevelRange = { top: 200, bottom: -200 }; // 电平范围
let showLevelRange: LevelRange = { top: 30, bottom: -170 }; // 显示电平范围
let fftHeaps = false; // 频域图堆积

// const minWav: number = -16_384;
// const maxWav: number = 16_384;
const rowNum = 5; // 行
const cloumnNum = 5; // 列
const maindiv = ref();
let painter: CanvasRenderingContext2D | null = null; //
const canvas = ref<HTMLCanvasElement | null>(null); // 画布

// 接收处理结果
const fftImage = ref<ImageBitmap>();
const maxFftImage = ref<ImageBitmap>();
const waterfallImage = ref<ImageBitmap>();
const waveImage = ref<ImageBitmap>();

// 图例相关
const legendImage = ref<ImageBitmap>();
const legendScheme = ref<string>('Hot');
const legendSteps = ref<number>(256);

const chooseShow = ref<boolean>(false);
let chooseIng = false;
let lastFftLevelRange: LevelRange = { top: 30, bottom: -170 };
// const selectRanges = ref<SelectRange[]>([]);

const chooseRange = ref<SelectRange>({ start: 0, end: 0 }); // 选择的频率范围

let mouseBeginX = 0; // 鼠标按下点
let mouseBeginY = 0; // 鼠标按下点
let mouseHoverX = 0; // 鼠标悬浮坐标点X
let mouseHoverY = 0;
let mouseEndX = 0; // 鼠标弹起点X
let mouseEndY = 0; // 鼠标弹起点Y
let selectFreq = false;
let moveFreq = false;
let selectLevel = false;
let moveLevel = false;
const subLineShow = true; // 辅助线显示功能开启
let subXLineShow = false; // 电平辅助线显示
let subYLineShow = false; // 频率辅助线显示
let nowFreq = 0;
let nowLevel = 0;

let isPainting = false;

// watch(
//   () => props.showMode,
//   (newVal: number) => {
//     setShowMode(newVal);
//   },
// );

// 使用命名处理函数，便于卸载时移除；在替换 ImageBitmap 前关闭旧的位图以释放内存
const workerMessageHandler = (event: MessageEvent<WorkerMessage>) => {
  const data = event.data;
  switch (data.type) {
    case 'colorLegend': {
      // 关闭旧的 legendImage（如果存在）以释放资源
      try {
        if (legendImage.value && (legendImage.value as any).close) {
          (legendImage.value as any).close();
        }
      } catch (e) {
        // ignore
      }
      // 接收渐变色图例
      legendImage.value = data.payload.image;
      legendScheme.value = data.payload.scheme;
      legendSteps.value = data.payload.steps;
      paint();

      break;
    }
    case 'fftLevelRange': {
      lastFftLevelRange = data.payload;
      paint();

      break;
    }
    case 'processedData': {
      // 在覆盖之前，关闭旧的 ImageBitmap（如果浏览器支持 close）
      try {
        if (fftImage.value && (fftImage.value as any).close) {
          (fftImage.value as any).close();
        }
      } catch (e) {
        // ignore close errors
        void e;
      }
      try {
        if (maxFftImage.value && (maxFftImage.value as any).close) {
          (maxFftImage.value as any).close();
        }
      } catch (e) {
        // ignore close errors
        void e;
      }
      try {
        if (waterfallImage.value && (waterfallImage.value as any).close) {
          (waterfallImage.value as any).close();
        }
      } catch (e) {
        // ignore close errors
        void e;
      }

      fftImage.value = data.payload.fftImage;
      maxFftImage.value = data.payload.maxFftImage;
      waterfallImage.value = data.payload.waterfallImage;
      paint();

      break;
    }
    // No default
  }
};

worker.addEventListener('message', workerMessageHandler);

// 发送显示频率范围到worker
const sendShowFreqRange = (range: FreqRange) => {
  showFreqRange = range;
  worker.postMessage({
    type: 'setShowFreqRange',
    payload: showFreqRange,
  });
};

// 发送显示电平范围到worker
const sendShowLevelRange = (range: LevelRange) => {
  showLevelRange = range;
  worker.postMessage({
    type: 'setShowLevelRange',
    payload: showLevelRange,
  });
};

// 发送频域数据到worker
const sendFftData = (data: number[], startFreq: number, stopFreq: number) => {
  worker.postMessage({
    type: 'setFftData',
    payload: {
      data,
      startFreq,
      stopFreq,
    },
  });
};

// 发送频域数据到worker
const sendWaveData = (data: number[]) => {
  worker.postMessage({
    type: 'setWaveData',
    payload: {
      data,
    },
  });
};

// 发送是否计算最大值到worker
const sendComputeMaxFft = (computeMaxFft: boolean) => {
  worker.postMessage({
    type: 'setComputeMaxFft',
    payload: {
      computeMaxFft,
    },
  });
};

// 设置显示类型
const setShowMode = (mode: number) => {
  showMode.value = mode;
  resetRect();
};

// 设置是否fft最大值保持
const setFftHeaps = (value: boolean) => {
  fftHeaps = value;
  sendComputeMaxFft(fftHeaps);
};

// 设置颜色映射方案
const setColorMap = (scheme: string, steps?: number) => {
  worker.postMessage({
    type: 'setColorMap',
    payload: {
      scheme,
      steps: steps || 256,
    },
  });
  legendScheme.value = scheme;
  if (steps) legendSteps.value = steps;
};

// fft数据更新
const appendFftData = (data: number[], startFreq: number, stopFreq: number) => {
  sendFftData(data, startFreq, stopFreq);
};

// 波形数据更新
const appendWaveData = (data: number[]) => {
  sendWaveData(data);
  paint();
};

const setChooseFreq = (leftFreq: number, rightFreq: number) => {
  chooseRange.value.start = leftFreq;
  chooseRange.value.end = rightFreq;
  chooseShow.value = true;
  paint();
};
// 设置频谱电平自适应
const levelAdaptive = () => {
  showLevelRange.top =
    lastFftLevelRange.top +
    (lastFftLevelRange.top - lastFftLevelRange.bottom) * 0.1;
  showLevelRange.bottom =
    lastFftLevelRange.bottom -
    (lastFftLevelRange.top - lastFftLevelRange.bottom) * 0.1;
  sendShowLevelRange(showLevelRange);
  paint();
};

// 频率范围
const setFreqRange = (range: FreqRange) => {
  if (range.left !== freqRange.left || range.right !== freqRange.right) {
    freqRange = range;
    showFreqRange = range;

    sendShowFreqRange(showFreqRange);
    paint();
  }
};

// 重置画布
const resetRect = () => {
  const canvasElement = canvas.value;
  if (canvasElement) {
    // 使用 CSS.escape 以防 id 中含有特殊字符
    const container = document.querySelector(
      `#${CSS.escape(div_id)}`,
    ) as HTMLElement | null;
    if (container) {
      canvasElement.width = container.clientWidth as number;
      canvasElement.height = container.clientHeight as number;
    }

    // 全部归0
    fftRect = new ViewRect(0, 0, 0, 0);
    freqRect = new ViewRect(0, 0, 0, 0);
    levelRect = new ViewRect(0, 0, 0, 0);
    waveRect = new ViewRect(0, 0, 0, 0);
    fullRect = new ViewRect(0, 0, 0, 0);
    legendRect = new ViewRect(0, 0, 0, 0);
    //
    switch (showMode.value) {
      case ShowModeEnum.FFT: {
        fftRect = new ViewRect(
          leftPadding,
          canvasElement.width - rightPadding,
          topPadding,
          canvasElement.height - bottomPadding,
        );
        freqRect = new ViewRect(
          fftRect.left,
          fftRect.right,
          fftRect.bottom,
          canvasElement.height,
        );
        levelRect = new ViewRect(
          fftRect.right,
          canvasElement.width,
          fftRect.top,
          fftRect.bottom,
        );

        break;
      }
      case ShowModeEnum.FFT_FULL: {
        fftRect = new ViewRect(
          leftPadding,
          canvasElement.width - rightPadding,
          topPadding,
          canvasElement.height / 2 - bottomPadding,
        );
        freqRect = new ViewRect(
          fftRect.left,
          fftRect.right,
          fftRect.bottom,
          canvasElement.height / 2,
        );
        levelRect = new ViewRect(
          fftRect.right,
          canvasElement.width,
          fftRect.top,
          fftRect.bottom,
        );
        fullRect = new ViewRect(
          leftPadding,
          canvasElement.width - rightPadding,
          canvasElement.height / 2 + topPadding,
          canvasElement.height - bottomPadding,
        );
        legendRect = new ViewRect(
          fullRect.right,
          canvasElement.width,
          fullRect.top,
          fullRect.bottom,
        );

        break;
      }
      case ShowModeEnum.FFT_WAVE: {
        fftRect = new ViewRect(
          leftPadding,
          canvasElement.width - rightPadding,
          topPadding,
          canvasElement.height / 2 - bottomPadding,
        );
        freqRect = new ViewRect(
          fftRect.left,
          fftRect.right,
          fftRect.bottom,
          canvasElement.height / 2,
        );
        levelRect = new ViewRect(
          fftRect.right,
          canvasElement.width,
          fftRect.top,
          fftRect.bottom,
        );
        waveRect = new ViewRect(
          leftPadding,
          canvasElement.width - rightPadding,
          canvasElement.height / 2 + topPadding,
          canvasElement.height - bottomPadding,
        );

        break;
      }
      case ShowModeEnum.FULL: {
        fullRect = new ViewRect(
          leftPadding,
          canvasElement.width - rightPadding,
          topPadding,
          canvasElement.height - bottomPadding,
        );
        legendRect = new ViewRect(
          fullRect.right,
          canvasElement.width,
          fullRect.top,
          fullRect.bottom,
        );

        break;
      }
      case ShowModeEnum.WAVE: {
        waveRect = new ViewRect(
          leftPadding,
          canvasElement.width - rightPadding,
          topPadding,
          canvasElement.height - bottomPadding,
        );

        break;
      }
      // No default
    }
  }
  paint();
};

const drawFft = () => {
  if (!painter) return;
  if (!fftImage.value) return;
  painter.drawImage(
    fftImage.value,
    fftRect.left,
    fftRect.top,
    fftRect.width,
    fftRect.height,
  );
};

const drawMaxFft = () => {
  if (!fftHeaps) return;
  if (!painter) return;
  if (!maxFftImage.value) return;
  painter.drawImage(
    maxFftImage.value,
    fftRect.left,
    fftRect.top,
    fftRect.width,
    fftRect.height,
  );
};

const drawWave = () => {
  if (!painter) return;
  if (!waveImage.value) return;
  painter.drawImage(
    waveImage.value,
    waveRect.left,
    waveRect.top,
    waveRect.width,
    waveRect.height,
  );

  // if (!painter) return;
  // painter.strokeStyle = '#f5d37f';
  // painter.lineWidth = 1;
  // painter.save();
  // painter.beginPath();
  // // canvasElement.clipRect(fftRect.left, fftRect.top, fftRect.width, fftRect.height)
  // const step = waveData.length / waveRect.width;
  // for (let i = 1; i < waveData.length; i++) {
  //   painter.moveTo(
  //     (i - 1) * step,
  //     ((maxWav - waveData[i - 1]) / (maxWav - minWav)) * waveRect.height +
  //       waveRect.top,
  //   );
  //   painter.lineTo(
  //     i * step,
  //     ((maxWav - waveData[i]) / (maxWav - minWav)) * waveRect.height +
  //       waveRect.top,
  //   );
  // }
  // painter.rect(waveRect.left, waveRect.top, waveRect.width, waveRect.height);
  // painter.clip();
  // painter.closePath();
  // painter.stroke();
  // painter.restore();
};

const drawFull = () => {
  if (!painter) return;
  if (!waterfallImage.value) return;
  painter.drawImage(
    waterfallImage.value,
    fullRect.left,
    fullRect.top,
    fullRect.width,
    fullRect.height,
  );
};

const drawLegend = () => {
  if (!painter || !legendImage.value) return;
  painter.save();

  // 绘制渐变色图例
  const legendWidth = legendRect.width / 4;
  const legendX = legendRect.left + (legendRect.width * 3) / 4;
  painter.drawImage(
    legendImage.value,
    legendX,
    legendRect.top,
    legendWidth,
    legendRect.height,
  );

  // 绘制图例边框
  painter.strokeStyle = '#666';
  painter.lineWidth = 1;
  painter.strokeRect(legendX, legendRect.top, legendWidth, legendRect.height);

  // 绘制刻度标签
  painter.fillStyle = '#333';
  painter.font = '10px Arial';
  painter.textAlign = 'left';

  // 顶部标签 (最大值)
  const topLabel = `${showLevelRange.top.toFixed(0)}dBm`;
  painter.fillText(topLabel, legendX + legendWidth + 5, legendRect.top + 10);

  // 底部标签 (最小值)
  const bottomLabel = `${showLevelRange.bottom.toFixed(0)}dBm`;
  painter.fillText(
    bottomLabel,
    legendX + legendWidth + 5,
    legendRect.bottom - 5,
  );

  // 中间标签
  const midValue = (showLevelRange.top + showLevelRange.bottom) / 2;
  const midLabel = `${midValue.toFixed(0)}dBm`;
  const midY = legendRect.top + legendRect.height / 2;
  painter.fillText(midLabel, legendX + legendWidth + 5, midY + 3);

  painter.restore();
};

const drawWaveGrid = () => {
  if (!painter) return;
  painter.save();
  painter.strokeStyle = canvas.value?.style.color as string;
  painter.lineWidth = 0.5;
  painter.beginPath();

  // 画横线
  for (let i = 0; i <= rowNum; i++) {
    painter.moveTo(
      waveRect.left,
      (waveRect.height / rowNum) * i + waveRect.top,
    );
    painter.lineTo(
      waveRect.right,
      (waveRect.height / rowNum) * i + waveRect.top,
    );
  }
  painter.stroke();
  painter.closePath();
  painter.restore();
};
const measureText = (font: string, text: string) => {
  const spanDom = document.createElement('span');
  spanDom.style.margin = '0';
  spanDom.style.font = font;
  spanDom.style.opacity = '0';
  spanDom.innerHTML = text;
  document.body.append(spanDom);
  const sizeD: { height: number; width: number } = { width: 0, height: 0 };
  sizeD.width = spanDom.offsetWidth;
  sizeD.height = spanDom.offsetHeight / 2;
  spanDom.remove();
  return sizeD;
};

const drawFreq = () => {
  if (!painter) return;
  painter.strokeStyle = '#f8fafa';
  painter.fillStyle = '#f8fafa';
  for (let i = 0; i <= cloumnNum; i++) {
    const freqStr = `${(
      showFreqRange.left +
      ((showFreqRange.right - showFreqRange.left) / cloumnNum) * i
    ).toFixed(2)} ${props.freqSuffix}`;
    const halfwidth = painter.measureText(freqStr).width / 2;
    const halfHeight = measureText(painter.font, freqStr).height;
    if (i === 0) {
      painter.fillText(
        freqStr,
        fftRect.left,
        fftRect.bottom + halfHeight,
        painter.measureText(freqStr).width,
      );
    } else {
      painter.fillText(
        freqStr,
        (fftRect.width / cloumnNum) * i + leftPadding - halfwidth,
        fftRect.bottom + halfHeight,
        painter.measureText(freqStr).width,
      );
      // painter.strokeText(freqStr, fftRect.width / cloumnNum * i + leftPadding, canvasElement.height - bottomPadding, painter.measureText(freqStr).width)
    }
  }
};
const drawLevel = () => {
  if (!painter) return;
  painter.strokeStyle = '#f8fafa';
  painter.fillStyle = '#f8fafa';
  for (let i = 0; i <= rowNum; i++) {
    const levelStr = `${(
      showLevelRange.top -
      ((showLevelRange.top - showLevelRange.bottom) / rowNum) * i
    ).toFixed(1)} ${props.levelSuffix}`;
    const halfHeight = measureText(painter.font, levelStr).height / 2;
    if (i === rowNum) {
      painter.fillText(
        levelStr,
        fftRect.right,
        fftRect.bottom,
        painter.measureText(levelStr).width,
      );
    } else {
      painter.fillText(
        levelStr,
        fftRect.right,
        (fftRect.height / rowNum) * i + topPadding + halfHeight,
        painter.measureText(levelStr).width,
      );
      // painter.strokeText(freqStr, fftRect.width / cloumnNum * i + leftPadding, canvasElement.height - bottomPadding, painter.measureText(freqStr).width)
    }
  }
};

// helper functions (unused) left with underscore-prefixed variants

const drawChoose = () => {
  if (!painter) return;
  painter.save();
  const startX =
    ((chooseRange.value.start - showFreqRange.left) /
      (showFreqRange.right - showFreqRange.left)) *
      fftRect.width +
    fftRect.left;
  const endX =
    ((chooseRange.value.end - showFreqRange.left) /
      (showFreqRange.right - showFreqRange.left)) *
      fftRect.width +
    fftRect.left;
  // 创建一个渐变色线性对象
  const grad = painter.createLinearGradient(
    Math.min(startX, endX),
    0,
    Math.max(startX, endX),
    0,
  );
  // 设置渐变颜色
  grad.addColorStop(0, 'rgba(22,184,200,0.47)');
  grad.addColorStop(0.5, 'rgba(82,67,192,0.47)');
  grad.addColorStop(1, 'rgba(22,184,200,0.47)');
  // 设置fillStyle为当前的渐变对象
  painter.fillStyle = grad;
  // 绘制渐变图形
  painter.fillRect(
    Math.min(startX, endX),
    fftRect.top,
    Math.abs(endX - startX),
    fftRect.height,
  );
  // restore will reset styles, but ensure we don't assign an empty string
  painter.fillStyle = 'transparent';
  painter.restore();
};
const drawSelectFreq = () => {
  if (!painter) return;
  painter.save();
  painter.fillStyle = 'rgba(73,114,248,0.87)';
  painter.fillRect(
    mouseBeginX,
    fftRect.top,
    mouseEndX - mouseBeginX,
    fftRect.height + freqRect.height,
  );
  painter.fillStyle = 'transparent';
  painter.restore();
};
const drawSelectLevel = () => {
  if (!painter) return;
  painter.save();
  painter.fillStyle = 'rgba(73,114,248,0.87)';
  painter.fillRect(
    leftPadding,
    mouseBeginY,
    freqRect.width + levelRect.width,
    mouseEndY - mouseBeginY,
  );
  painter.fillStyle = 'transparent';
  painter.restore();
};
const drawFftGrid = () => {
  if (!painter) return;
  painter.save();
  painter.strokeStyle = '#cfd9da';
  painter.lineWidth = 0.5;
  painter.beginPath();

  // 画横线
  for (let i = 0; i <= rowNum; i++) {
    painter.moveTo(fftRect.left, (fftRect.height / rowNum) * i + fftRect.top);
    painter.lineTo(fftRect.right, (fftRect.height / rowNum) * i + fftRect.top);
  }

  // 画纵线
  for (let i = 0; i <= cloumnNum; i++) {
    painter.moveTo((fftRect.width / cloumnNum) * i + fftRect.left, fftRect.top);
    painter.lineTo(
      (fftRect.width / cloumnNum) * i + fftRect.left,
      fftRect.bottom,
    );
  }
  painter.stroke();
  painter.closePath();
  painter.restore();
};
const drawSubLine = () => {
  if (!painter) return;
  painter.save();
  painter.strokeStyle = '#EB3324';
  painter.lineWidth = 1;
  painter.beginPath();

  const freqStr = `频率：${nowFreq.toFixed(2)} ${props.freqSuffix}`;
  const levelStr = `电平：${nowLevel.toFixed(2)} ${props.levelSuffix}`;

  if (subXLineShow) {
    painter.moveTo(fftRect.left, mouseHoverY);
    painter.lineTo(levelRect.right, mouseHoverY);
    painter.fillText(
      levelStr,
      fftRect.left,
      fftRect.bottom - 8,
      painter.measureText(levelStr).width,
    );
  }

  if (subYLineShow) {
    painter.moveTo(mouseHoverX, fftRect.top);
    painter.lineTo(mouseHoverX, freqRect.bottom);
    painter.fillText(
      freqStr,
      fftRect.left,
      fftRect.bottom - 20,
      painter.measureText(freqStr).width,
    );
  }
  painter.stroke();
  painter.closePath();
  painter.restore();
};

const paint = () => {
  if (isPainting) return;
  // const start = performance.now();
  isPainting = true;
  if (painter && canvas.value) {
    painter.clearRect(0, 0, canvas.value.width, canvas.value.height);
  }

  // drawFreqBand()
  if (
    showMode.value === ShowModeEnum.FFT ||
    showMode.value === ShowModeEnum.FFT_WAVE ||
    showMode.value === ShowModeEnum.FFT_FULL
  )
    drawFftGrid();
  if (
    showMode.value === ShowModeEnum.FFT ||
    showMode.value === ShowModeEnum.FFT_WAVE ||
    showMode.value === ShowModeEnum.FFT_FULL
  )
    drawFft();
  if (
    showMode.value === ShowModeEnum.FFT ||
    showMode.value === ShowModeEnum.FFT_WAVE ||
    showMode.value === ShowModeEnum.FFT_FULL
  )
    drawMaxFft();
  if (chooseShow.value) drawChoose();
  if (
    showMode.value === ShowModeEnum.FFT ||
    showMode.value === ShowModeEnum.FFT_WAVE ||
    showMode.value === ShowModeEnum.FFT_FULL
  )
    drawFreq();
  if (
    showMode.value === ShowModeEnum.FFT ||
    showMode.value === ShowModeEnum.FFT_WAVE ||
    showMode.value === ShowModeEnum.FFT_FULL
  )
    drawLevel();
  if (selectFreq) drawSelectFreq();
  if (selectLevel) drawSelectLevel();
  if (
    showMode.value === ShowModeEnum.FULL ||
    showMode.value === ShowModeEnum.FFT_FULL
  )
    drawLegend();
  if (
    showMode.value === ShowModeEnum.FULL ||
    showMode.value === ShowModeEnum.FFT_FULL
  )
    drawFull();
  if (
    showMode.value === ShowModeEnum.WAVE ||
    showMode.value === ShowModeEnum.FFT_WAVE
  )
    drawWave();
  if (
    showMode.value === ShowModeEnum.WAVE ||
    showMode.value === ShowModeEnum.FFT_WAVE
  )
    drawWaveGrid();
  if (subLineShow) drawSubLine();
  isPainting = false;
  // const end = performance.now();
  // console.log(`==================重绘时间: ${end - start} ms`);
};

const canvasDown = (e: {
  button: number;
  clientX: number;
  clientY: number;
}) => {
  if (!canvas.value) return;
  const canvasRect = canvas.value.getBoundingClientRect();
  mouseBeginX = e.clientX - canvasRect.x;
  mouseBeginY = e.clientY - canvasRect.y;
  mouseEndX = mouseBeginX;
  mouseEndY = mouseBeginY;
  if (
    e.button === 0 &&
    mouseBeginX > fftRect.left &&
    mouseBeginX < fftRect.right &&
    mouseBeginY > fftRect.top &&
    mouseBeginY < fftRect.bottom
  ) {
    chooseIng = true;
    chooseShow.value = true;
    chooseRange.value.start =
      ((mouseBeginX - fftRect.left) / fftRect.width) *
        (showFreqRange.right - showFreqRange.left) +
      showFreqRange.left;
  }
  if (
    mouseBeginX > freqRect.left &&
    mouseBeginX < freqRect.right &&
    mouseBeginY > freqRect.top &&
    mouseBeginY < freqRect.bottom
  ) {
    if (e.button === 2) {
      selectFreq = true;
    } else if (e.button === 0) {
      moveFreq = true;
    }
  }
  if (
    mouseBeginX > levelRect.left &&
    mouseBeginX < levelRect.right &&
    mouseBeginY > levelRect.top &&
    mouseBeginY < levelRect.bottom
  ) {
    if (e.button === 2) {
      selectLevel = true;
    } else if (e.button === 0) {
      moveLevel = true;
    }
  }
};
const canvasMove = (e: { clientX: number; clientY: number }) => {
  if (!canvas.value) return;
  const canvasRect = canvas.value.getBoundingClientRect();
  mouseHoverX = e.clientX - canvasRect.x;
  mouseHoverY = e.clientY - canvasRect.y;
  mouseEndX = mouseHoverX;
  mouseEndY = mouseHoverY;

  if (
    subLineShow &&
    (showMode.value === ShowModeEnum.FFT ||
      showMode.value === ShowModeEnum.FULL ||
      showMode.value === ShowModeEnum.FFT_WAVE ||
      showMode.value === ShowModeEnum.FFT_FULL)
  ) {
    const wanthFreq = Math.abs(showFreqRange.left - showFreqRange.right);
    nowFreq =
      showFreqRange.left +
      ((mouseHoverX - leftPadding) / fftRect.width) * wanthFreq;
  }
  if (subLineShow && showMode.value === ShowModeEnum.FFT) {
    // 全FFT时计算电平
    const wanthLevel = Math.abs(showLevelRange.top - showLevelRange.bottom);
    nowLevel =
      showLevelRange.top -
      (wanthLevel * (mouseHoverY - topPadding)) / fftRect.height;
  }

  if (
    showMode.value === ShowModeEnum.FFT_WAVE ||
    showMode.value === ShowModeEnum.FFT_FULL
  ) {
    // 一半fft时计算电平
    const wanthLevel = Math.abs(showLevelRange.top - showLevelRange.bottom);
    nowLevel =
      showLevelRange.top -
      (wanthLevel * (mouseHoverY - topPadding)) / (fftRect.height / 2);
  }

  subYLineShow = !!(
    mouseHoverX > fftRect.left &&
    mouseHoverX < fftRect.right &&
    mouseHoverY > fftRect.top &&
    mouseHoverY < freqRect.bottom
  );

  subXLineShow = !!(
    mouseHoverX > fftRect.left &&
    mouseHoverX < levelRect.right &&
    mouseHoverY > fftRect.top &&
    mouseHoverY < fftRect.bottom
  );

  if (chooseIng) {
    chooseRange.value.end =
      ((mouseEndX - fftRect.left) / fftRect.width) *
        (showFreqRange.right - showFreqRange.left) +
      showFreqRange.left;
  }
  if (moveFreq) {
    const moveVal =
      ((showFreqRange.right - showFreqRange.left) / freqRect.width) *
      (mouseBeginX - mouseEndX);
    if (
      showFreqRange.left + moveVal >= freqRange.left &&
      showFreqRange.right + moveVal <= freqRange.right
    ) {
      showFreqRange.left += moveVal;
      showFreqRange.right += moveVal;
      sendShowFreqRange({
        left: showFreqRange.left,
        right: showFreqRange.right,
      });
    }
    mouseBeginX = mouseEndX;
    mouseBeginY = mouseEndY;
  }
  if (moveLevel) {
    const moveVal =
      ((showLevelRange.top - showLevelRange.bottom) / levelRect.height) *
      (mouseEndY - mouseBeginY);
    if (
      showLevelRange.top + moveVal <= levelRange.top &&
      showLevelRange.bottom + moveVal >= levelRange.bottom
    ) {
      showLevelRange.top += moveVal;
      showLevelRange.bottom += moveVal;
      sendShowLevelRange({
        bottom: showLevelRange.bottom,
        top: showLevelRange.top,
      });
    }
    mouseBeginX = mouseEndX;
    mouseBeginY = mouseEndY;
  }
  // if (selectFreq || selectLevel || chooseIng || moveFreq || moveLevel)
  paint();
};
const canvasUp = (e: { clientX: number; clientY: number }) => {
  if (!canvas.value) return;
  const canvasRect = canvas.value.getBoundingClientRect();
  mouseEndX = e.clientX - canvasRect.x;
  mouseEndY = e.clientY - canvasRect.y;
  if (chooseIng) {
    chooseRange.value.end =
      ((mouseEndX - fftRect.left) / fftRect.width) *
        (showFreqRange.right - showFreqRange.left) +
      showFreqRange.left;
    if (chooseRange.value.end < chooseRange.value.start) {
      const freq = chooseRange.value.end;
      chooseRange.value.end = chooseRange.value.start;
      chooseRange.value.start = freq;
    }
    if (chooseRange.value.end === chooseRange.value.start) {
      chooseShow.value = false;
    } else {
      // 发送信号
      // proxy.emit('chooseFreqChange', chooseRange.value.start, chooseRange.value.end)
    }
    // alert('框选开始频率:' + chooseBeginFreq + '框选结束频率' + chooseEndFreq)
  }
  if (selectFreq) {
    const beginFreq =
      ((mouseBeginX > mouseEndX ? mouseEndX : mouseBeginX - freqRect.left) /
        freqRect.width) *
        (showFreqRange.right - showFreqRange.left) +
      showFreqRange.left;
    const endFreq =
      ((mouseBeginX > mouseEndX ? mouseBeginX : mouseEndX - freqRect.left) /
        freqRect.width) *
        (showFreqRange.right - showFreqRange.left) +
      showFreqRange.left;
    sendShowFreqRange({ left: beginFreq, right: endFreq });
  }
  if (selectLevel) {
    const newBottom =
      showLevelRange.top -
      ((mouseBeginY > mouseEndY ? mouseBeginY : mouseEndY - levelRect.top) /
        levelRect.height) *
        (showLevelRange.top - showLevelRange.bottom);
    const newTop =
      showLevelRange.top -
      ((mouseBeginY > mouseEndY ? mouseEndY : mouseBeginY - levelRect.top) /
        levelRect.height) *
        (showLevelRange.top - showLevelRange.bottom);
    showLevelRange.bottom = newBottom;
    showLevelRange.top = newTop;
    sendShowLevelRange({
      bottom: showLevelRange.bottom,
      top: showLevelRange.top,
    });
  }
  chooseIng = false;
  selectFreq = false;
  moveFreq = false;
  selectLevel = false;
  moveLevel = false;
  paint();
};
const canvasDblClick = (e: { button: number }) => {
  // 重置频率区域
  if (
    e.button === 0 &&
    mouseHoverX > freqRect.left &&
    mouseHoverX < freqRect.right &&
    mouseHoverY > freqRect.top &&
    mouseHoverY < freqRect.bottom
  ) {
    sendShowFreqRange({ left: freqRange.left, right: freqRange.right });
    paint();
  }
  // 重置电平区域
  if (
    e.button === 0 &&
    mouseHoverX > levelRect.left &&
    mouseHoverX < levelRect.right &&
    mouseHoverY > levelRect.top &&
    mouseHoverY < levelRect.bottom
  ) {
    showLevelRange.bottom = levelRange.bottom;
    showLevelRange.top = levelRange.top;
    sendShowLevelRange(showLevelRange);
    paint();
  }
};
const canvasWheel = (e: any) => {
  if (e.wheelDelta > 0 || e.detail < 0) {
    if (
      mouseHoverX > freqRect.left &&
      mouseHoverX < freqRect.right &&
      mouseHoverY > freqRect.top &&
      mouseHoverY < freqRect.bottom
    ) {
      const changeVal = (showFreqRange.right - showFreqRange.left) / 10;
      const changeLeftVal =
        ((mouseHoverX - freqRect.left) / freqRect.width) * changeVal;
      const changeRightVal = changeVal - changeLeftVal;
      showFreqRange.left += changeLeftVal;
      showFreqRange.right -= changeRightVal;
      sendShowFreqRange({
        left: showFreqRange.left,
        right: showFreqRange.right,
      });
    }
    if (
      mouseHoverX > levelRect.left &&
      mouseHoverX < levelRect.right &&
      mouseHoverY > levelRect.top &&
      mouseHoverY < levelRect.bottom
    ) {
      const changeVal = (showLevelRange.top - showLevelRange.bottom) / 10;
      const changeTopVal =
        ((mouseHoverY - levelRect.top) / levelRect.height) * changeVal;
      const changeBottomVal = changeVal - changeTopVal;
      showLevelRange.top -= changeTopVal;
      showLevelRange.bottom += changeBottomVal;
      sendShowLevelRange({
        bottom: showLevelRange.bottom,
        top: showLevelRange.top,
      });
    }
  } else {
    if (
      mouseHoverX > freqRect.left &&
      mouseHoverX < freqRect.right &&
      mouseHoverY > freqRect.top &&
      mouseHoverY < freqRect.bottom
    ) {
      const changeVal = (showFreqRange.right - showFreqRange.left) / 9;
      const changeLeftVal =
        ((mouseHoverX - freqRect.left) / freqRect.width) * changeVal;
      const changeRightVal = changeVal - changeLeftVal;
      if (showFreqRange.left - changeLeftVal < freqRange.left) {
        showFreqRange.left = freqRange.left;
      } else {
        showFreqRange.left -= changeLeftVal;
      }
      if (showFreqRange.right + changeRightVal > freqRange.right) {
        showFreqRange.right = freqRange.right;
      } else {
        showFreqRange.right += changeRightVal;
      }
      sendShowFreqRange({
        left: showFreqRange.left,
        right: showFreqRange.right,
      });
    }
    if (
      mouseHoverX > levelRect.left &&
      mouseHoverX < levelRect.right &&
      mouseHoverY > levelRect.top &&
      mouseHoverY < levelRect.bottom
    ) {
      const changeVal = (showLevelRange.top - showLevelRange.bottom) / 10;
      const changeTopVal =
        ((mouseHoverY - levelRect.top) / levelRect.height) * changeVal;
      const changeBottomVal = changeVal - changeTopVal;
      if (showLevelRange.top + changeTopVal > levelRange.top) {
        showLevelRange.top = levelRange.top;
      } else {
        showLevelRange.top += changeTopVal;
      }
      if (showLevelRange.bottom - changeBottomVal < levelRange.bottom) {
        showLevelRange.bottom = levelRange.bottom;
      } else {
        showLevelRange.bottom -= changeBottomVal;
      }
      sendShowLevelRange({
        bottom: showLevelRange.bottom,
        top: showLevelRange.top,
      });
    }
  }
  paint();
};
const canvasOver = () => {
  // console.log('移入')
};
const canvasOut = (e: { clientX: number; clientY: number }) => {
  if (chooseIng) {
    if (canvas.value) {
      mouseEndX = e.clientX - canvas.value.offsetLeft;
      mouseEndY = e.clientY - canvas.value.offsetTop;
    }
    chooseIng = false;
  }
  selectFreq = false;
  moveFreq = false;
  selectLevel = false;
  moveLevel = false;
  subXLineShow = false;
  subYLineShow = false;
};

// 处理尺寸变化的回调函数
const handleResize = (entries: ResizeObserverEntry[]) => {
  for (const entry of entries) {
    if (
      entry.target === maindiv.value && // 在这里可以添加处理逻辑，例如调整 canvas 尺寸或重新绘制内容
      canvas.value
    ) {
      resetRect();
      // 调用绘图函数或其他操作
    }
  }
};

const onContextMenu = (e: Event) => e.preventDefault();

sendShowFreqRange(showFreqRange);
sendShowLevelRange(showLevelRange);
sendComputeMaxFft(fftHeaps);

onMounted(() => {
  maindiv.value = document.querySelector(`#${CSS.escape(div_id)}`);
  canvas.value = document.querySelector(
    `#${CSS.escape(canvas_id)}`,
  ) as HTMLCanvasElement;
  const canvasElement = canvas.value;
  if (!canvasElement) return;
  canvasElement.width = 200;
  canvasElement.height = 100;
  painter = canvasElement.getContext('2d');
  if (!painter) return;
  painter.fillStyle = 'rgb(133,155,238)';

  canvasElement.addEventListener('contextmenu', onContextMenu);
  canvasElement.addEventListener('mousedown', canvasDown);
  canvasElement.addEventListener('mousemove', canvasMove);
  canvasElement.addEventListener('mouseup', canvasUp);
  canvasElement.addEventListener('dblclick', canvasDblClick);
  canvasElement.addEventListener('wheel', canvasWheel);
  canvasElement.addEventListener('mouseover', canvasOver);
  canvasElement.addEventListener('mouseout', canvasOut);

  if (maindiv.value) {
    // 创建大小改变监听器
    resizeObserver = new ResizeObserver(handleResize);
    resizeObserver.observe(maindiv.value);
  } else {
    console.warn('maindiv is not available');
  }

  sendShowFreqRange(showFreqRange);
  sendShowLevelRange(showLevelRange);
  sendComputeMaxFft(fftHeaps);
});

onUnmounted(() => {
  // 移除 canvas 事件监听器
  if (canvas.value) {
    const canvasElement = canvas.value;
    canvasElement.removeEventListener('contextmenu', onContextMenu);
    canvasElement.removeEventListener('mousedown', canvasDown);
    canvasElement.removeEventListener('mousemove', canvasMove);
    canvasElement.removeEventListener('mouseup', canvasUp);
    canvasElement.removeEventListener('dblclick', canvasDblClick);
    canvasElement.removeEventListener('wheel', canvasWheel);
    canvasElement.removeEventListener('mouseover', canvasOver);
    canvasElement.removeEventListener('mouseout', canvasOut);
  }
  // 移除观察器
  if (resizeObserver && maindiv.value) {
    try {
      resizeObserver.unobserve(maindiv.value);
    } catch {
      // ignore
    }
    try {
      resizeObserver.disconnect();
    } catch {
      // ignore
    }
  }

  // 销毁 worker
  try {
    if (worker) worker.terminate();
  } catch {
    // ignore
  }
  // 移除 worker 事件监听（如果使用命名 handler）
  try {
    worker.removeEventListener('message', workerMessageHandler as any);
  } catch (e) {
    void e;
  }

  // 释放 ImageBitmap 资源
  try {
    if (fftImage.value && (fftImage.value as any).close) (fftImage.value as any).close();
  } catch (e) {
    void e;
  }
  try {
    if (maxFftImage.value && (maxFftImage.value as any).close) (maxFftImage.value as any).close();
  } catch (e) {
    void e;
  }
  try {
    if (waterfallImage.value && (waterfallImage.value as any).close) (waterfallImage.value as any).close();
  } catch (e) {
    void e;
  }

  // 清理画布上下文引用，帮助 GC
  painter = null;
});

defineExpose({
  levelAdaptive, // 设置电平自适应
  setFreqRange, // 设置坐标开始起止
  setShowMode, // 设置显示模式
  setFftHeaps, // 设置FFT堆积
  setColorMap, // 设置颜色映射方案
  setChooseFreq, // 设置框选区域
  appendWaveData, // 添加时域数据
  appendFftData, // 添加频域数据
  resetRect, // 调整大小
});
</script>

<template>
  <div :id="div_id" class="main">
    <canvas :id="canvas_id" />
  </div>
</template>

<style scoped>
.main {
  width: 100%;
  height: 100%;
  background: transparent;
}
</style>
